﻿using System;

using System.Collections.Generic;
using System.Text;
using PublicTransport.Views;
using PublicTransport.Services;
using PublicTransport.DAL;
using PublicTransport.Services.BO;
using PublicTransport.Helpers;
using PublicTransport.Services.Enums;
using PublicTransport.DAL.DTO;
using System.Windows.Forms;
using PublicTransport.GpsNavigation;

namespace PublicTransport.Presenters
{
    /// <summary>
    /// Presenter pre vyhľadávacie používateľské rozhranie.
    /// </summary>
    class SearchPresenter
    {
        private ISearchView view;
        private INearestView nearestView;
        private IPathSearchService searchService;
        private IStationService stationService;
        private bool dataLoaded = false;
        private StationToSearch stationToSearch = null;

        /// <summary>
        /// Iniciuje SearchPresenter a prepojí s používateľským rozhraním.
        /// </summary>
        /// <param name="searchView">Používateľské rozhranie impelementujúce interface ISearchView</param>
        public SearchPresenter(ISearchView searchView)
        {
            view = searchView;
            searchService = new PathSearchingService();
            view.StartProgressBar();
            searchService.DataLoaded += new EventHandler(searchService_DataLoaded);
            searchService.AsyncLoad();
            stationService = StationService.Instance;

            view.SearchInitiated += OnSearchInitiated;
            view.ShowNearestStations += new EventHandler(view_ShowNearestStations);
            view.SetStationHint(stationService.GetAllStationNames().ToArray());

            //set current time
            DateTime currentTime = DateTime.Now;
            view.Hours = currentTime.Hour;
            view.Minutes = currentTime.Minute;

            //set the current daytype
            if (currentTime.DayOfWeek == DayOfWeek.Saturday || currentTime.DayOfWeek == DayOfWeek.Wednesday)
            {
                view.DayType = DayTypeEnum.Weekend;
            }
            else
            {
                view.DayType = DayTypeEnum.Work;
            }
        }

        /// <summary>
        /// Reakcie na event z používateľského prostredia - zobrazenie najbližších staníc
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void view_ShowNearestStations(object sender, EventArgs e)
        {
            ILocationService locationService = LocationService.Instance;
            locationService.Start();
            locationService.LocationChanged += new Microsoft.WindowsMobile.Samples.Location.LocationChangedEventHandler(locationService_LocationChanged);

            if (nearestView == null)
            {
                nearestView = new NearestStationsView();
                nearestView.setDestinationStation += new EventHandler(nearestView_setDestinationStation);
                nearestView.setStartStation += new EventHandler(nearestView_setStartStation);
            }
            nearestView.ShowForm();
        }

        /// <summary>
        /// Reakcia z používateľského rozhrania pre nastavenie štartovnej zastávky zo zoznamu
        /// najbližších staníc.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void nearestView_setStartStation(object sender, EventArgs e)
        {
            if (nearestView.getStation() != null)
                view.StartStation = nearestView.getStation();
        }

        /// <summary>
        /// Reakcia z používateľského rozhrania pre nastavenie cieľovej zastávky zo zoznamu
        /// najbližších staníc.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void nearestView_setDestinationStation(object sender, EventArgs e)
        {
            if (nearestView.getStation() != null)
                view.DestinationStation = nearestView.getStation();
        }

        /// <summary>
        /// Event vyvolaný v prípade zmeny GPS koordinátov zariadenia
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void locationService_LocationChanged(object sender, Microsoft.WindowsMobile.Samples.Location.LocationChangedEventArgs args)
        {
            SortedList<double, StationDTO> stations;
            if (!FakeGps.Instance.enabled()) stations = stationService.GetNearestStations(args.Position.Latitude, args.Position.Longitude);
            else
            {
                GpsPoint tmpPoint = FakeGps.Instance.getCoordinates();
                stations = stationService.GetNearestStations(tmpPoint.Y, tmpPoint.X);
            }

            if (nearestView != null) //&& nearestView.Visible)
            {
                nearestView.DisplayStations(stations);
                LocationService.Instance.Stop();
            }
        }

        /// <summary>
        /// Reakcia na event, keď skončí nahrávanie všetkých 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void searchService_DataLoaded(object sender, EventArgs e)
        {
            dataLoaded = true;
            view.StopProgressBar();
            //we need to execute this now - user is already waiting
            if (stationToSearch != null)
            {
                SearchTransits(stationToSearch.StartStation, stationToSearch.DestinationStation, stationToSearch.Time, stationToSearch.DayType);
                stationToSearch = null;
                view.SearchButtonEnabled = true;
            }
        }

        /// <summary>
        /// Reakcia na spustenie vyhľadávania z používateľského prostedia.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnSearchInitiated(object sender, EventArgs e)
        {
            String startStationName = view.StartStation;
            String destinationStationName = view.DestinationStation;

            if (startStationName == null || destinationStationName == null)
            {
                view.DisplayError("Zadajte obe stanice správne", false);
                return;
            }
            else
            {
                if (startStationName.Length == 0 || destinationStationName.Length == 0)
                {
                    view.DisplayError("Zadajte obe stanice správne", false);
                    return;
                }
            }

            //get the time
            int time = view.Hours * 100 + view.Minutes;
            //get daytype
            DayTypeEnum? dayType = view.DayType;

            if (dataLoaded == false)
            {
                view.SearchButtonEnabled = false;
                stationToSearch = new StationToSearch()
                {
                    StartStation = startStationName,
                    DestinationStation = destinationStationName,
                    DayType = (DayTypeEnum)dayType,
                    Time = time
                };
                return;
            }
            view.StartProgressBarSearch();
            for (int i = 0; i < 5; i++)
                Application.DoEvents();
            SearchTransits(startStationName, destinationStationName, time, dayType);

        }

        /// <summary>
        /// Vyhľadá spojenie medzi dvoma zastávkami v danom čase
        /// </summary>
        /// <param name="startStationName">Štartovná zastávka</param>
        /// <param name="destinationStationName">Cieľová zastávka</param>
        /// <param name="time">Čas v ktorom chceme vyhľadať spojenie</param>
        /// <param name="dayType">Typ ďna v ktorom hľadáme (pracovný, voľný, víkend)</param>
        private void SearchTransits(String startStationName, String destinationStationName, int time, DayTypeEnum? dayType)
        {
            StationDTO startStation = stationService.GetStation(startStationName);
            StationDTO destinationStation = stationService.GetStation(destinationStationName);

            List<List<PublicTransport.Services.Step2.Transit>> transits = searchService.FindPath((int)startStation.Id, (int)destinationStation.Id, time, (DayTypeEnum)dayType);

            if (transits != null && transits.Count > 0)
            {
                //make separate Presenter later
                view.StopProgressBarSearch();
                ResultView resultView = new ResultView(startStation.Name, destinationStation.Name, transits, new GpsPoint(startStation.Latitude.Value, startStation.Longtitude.Value));
                resultView.Show();
            }
            else
            {
                view.DisplayError("Nenašlo sa žiadne spojenie v danom čase", true);
            }
        }

        /// <summary>
        /// Pomocná trieda pre prenos dát informujúcich o detailoch vyhľadávania
        /// </summary>
        private class StationToSearch
        {
            public String StartStation { get; set; }
            public String DestinationStation { get; set; }
            public int Time { get; set; }
            public DayTypeEnum DayType { get; set; }
        }
    }
}
